﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Media.Imaging;
using System.Globalization;
using System.Collections;
using System.Windows.Controls;
using System.Collections.ObjectModel;
using System.IO;
using System.Windows.Media;
using System.Drawing;
using Lime49;
using System.Windows;
using LockCrypt.Core;
using System.Windows.Input;

namespace LockCrypt.Converters {
    /// <summary>
    /// Returns Visibility.Visible if any of the values parse to <c>true</c>, otherwise returns Visibility.Collapsed
    /// </summary>
    public class MultiBooleanToVisibilityConverter : IMultiValueConverter {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) {
            try {
                foreach(object val in values) {
                    if(System.Convert.ToBoolean(val)) {
                        return Visibility.Visible;
                    }
                }
                return Visibility.Collapsed;
            } catch {
                return Visibility.Visible;
            }
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Performs the opposite of BoolToVisibilityConverter, converting True to Visibility.Collapsed and False to Visibility.Hidden
    /// </summary>
    public class BoolToInvertedVisibilityConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            try {
                bool b = (bool)value;
                return b ? Visibility.Collapsed : Visibility.Visible;
            } catch {
                return 1;
            }
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Returns <c>false</c> if the string equivalent of <c>value</c> and <c>parameter</c> are equal, otherwise <c>true</c>.
    /// </summary>
    public class StringEqualityToInvertedBooleanConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            try {
                string val = System.Convert.ToString(value);
                string otherVal = System.Convert.ToString(parameter);
                return val != otherVal;
            } catch {
                return true;
            }
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Inverts a boolean value.
    /// </summary>
    public class BooleanInverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            try {
                bool b = (bool)value;
                return !b;
            } catch {
                return true;
            }
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            throw new NotImplementedException();
        }
    }


    /// <summary>
    /// Returns <c>Visibility.Visible</c> if <c>value</c> is a file-based database, otherwise returns <c>Visibility.Collapsed</c>.
    /// Inverts this behaviour if the parameter is '<c>inverted</c>'
    /// </summary>
    public class DatabaseModeIsFileBased : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            bool visible = true;
            try {
                Constants.DatabaseType dbType = (Constants.DatabaseType)Enum.Parse(typeof(Constants.DatabaseType), value.ToString(), true);
                switch(dbType) {
                    case Constants.DatabaseType.XML:
                    case Constants.DatabaseType.SQLite:
                    case Constants.DatabaseType.Legacy:
                        visible = true;
                        break;
                    default:
                        visible = false;
                        break;
                }
            } catch {
            }
            if(System.Convert.ToString(parameter).ToLowerInvariant() == "inverted") {
                return visible ? Visibility.Collapsed : Visibility.Visible;
            } else {
                return visible ? Visibility.Visible : Visibility.Collapsed;
            }
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Converts a delimited set of strings to a list and back again. The parameter defines the delimiter
    /// </summary>
    public class StringToListConverter : IValueConverter {
        /// <summary>
        /// Takes a string, returns a list seperated by {parameter}
        /// </summary>
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            string serializedList = (value ?? string.Empty).ToString(),
                   splitter = (parameter ?? string.Empty).ToString();
            if(serializedList.Trim().Length == 0) {
                return value;
            }
            return serializedList.Split(new[] { splitter }, StringSplitOptions.RemoveEmptyEntries).Reverse();
        }
        /// <summary>
        /// Takes a list, returns a string seperated by {parameter}
        /// </summary>
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            var items = value as IEnumerable;
            var splitter = (parameter ?? string.Empty).ToString();
            if(value == null || items == null) {
                return value;
            }
            StringBuilder buffer = new StringBuilder();
            foreach(var itm in items) {
                string stringEquivalent = System.Convert.ToString(itm);
                if(!string.IsNullOrEmpty(stringEquivalent)) {
                    buffer.Append(stringEquivalent).Append(splitter);
                }
            }
            return buffer.ToString(0, splitter.Length > 0 ? buffer.Length - splitter.Length : buffer.Length);
        }
    }

    /// <summary>
    /// Converts a comma separated list of values to a nicer list, replacing the last comma with 'and'.
    /// </summary>
    public class ListPrettifier : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            if(value == null || !(value is IEnumerable<string>)) {
                return value;
            }
            IEnumerable<string> list = value as IEnumerable<string>;
            return Utils.Implode(list, ", ", true, " and ");
        }
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Converts a value in seconds to something like:
    /// 2:30:15, or 30 Minutes or 15 seconds
    /// </summary>
    public class SecondsToTimeConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            int seconds = 0;
            int.TryParse((value ?? "0").ToString(), out seconds);
            TimeSpan time = TimeSpan.FromSeconds(seconds);
            double minuteComponents = (time.Minutes + Math.Max((double)time.Seconds, 0.01)) / 60; // who cares about 0.01 seconds, I doubt the meal will be ruined
            if(time.TotalSeconds == 0) {
                return 0;
            } else if(time.TotalHours -minuteComponents > 0) {
                return string.Format("{0}:{1}:{2}", (time.TotalHours - minuteComponents).ToString("00"), time.Minutes.ToString("00"), time.Seconds.ToString("00"));
            }else if(time.Minutes > 0 && time.Seconds == 0) { // from here down it's under an hour
                return string.Format("{0} {1}", time.Minutes, I18nUtils.GetString("Strings", "Minutes"));
            } else if(time.Seconds > 0 && time.Minutes == 0) {
                return string.Format("{0} {1}", time.Seconds, I18nUtils.GetString("Strings", "Seconds"));
            } else {
                return string.Format("{0}:{1}:{2}", (time.TotalHours - minuteComponents).ToString("00"), time.Minutes.ToString("00"), time.Seconds.ToString("00"));
            }
        }
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Converts a byte array to an image source.
    /// </summary>
    public class ByteToImageConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            if(value == null || !(value is byte[])) {
                return value;
            }
            BitmapImage img = new BitmapImage();
            using(MemoryStream ms = new MemoryStream((byte[])value)) {
                img.BeginInit();
                img.StreamSource = ms;
                img.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
                img.CacheOption = BitmapCacheOption.OnLoad;
                img.EndInit();
            }
            return img;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Converts two values to an ImageSource (values[0] = icon name, values[1] = icon size). This allows both values to be bound.
    /// If ba Parameter is supplied, it will act to specify the sub-directory of /Resources/ (do not include leading or trailing slashes).
    /// </summary>
    public class SizedImageConverter : IMultiValueConverter {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) {
            if(values == null || values.Length != 2)
                return values;
            string filename = (values[0] ?? string.Empty).ToString().Trim();
            string size = (values[1] ?? "32").ToString();
            string directory = (parameter ?? "Images/Templates").ToString();
            try {
                BitmapImage img = new BitmapImage();
                img.BeginInit();
                img.CacheOption = BitmapCacheOption.OnLoad;
                img.UriSource = new Uri("pack://application:,,,/LockCrypt.Core;component/Resources/" + string.Format("{0}/{1}_{2}.png", directory, filename, size));
                img.EndInit();
                return img;
            } catch(Exception ex) {
                Console.WriteLine(string.Format("Error loading image {0} ({1}px): ", filename, size, ex.Message));
            }
            return values;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// ==If used as an IValueConverter==
    /// Converts a string (icon name) and a parameter (icon size) to an ImageSource which can be used for showing account type icons.
    /// Only the icon name can be bound as the size is specified in the ConverterParameter
    /// Filename = Value
    /// Parameter = File size
    /// 
    /// ==If used as an IMultiValueConverter==
    /// Converts two values to an ImageSource. This allows both values to be bound.
    /// values[0] = icon name
    /// values[1] = icon size
    /// </summary>
    public class IconConverter : IValueConverter, IMultiValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            string filename = (value ?? string.Empty).ToString().Trim();
            if(filename.Length == 0)
                return null;
            string size = (parameter ?? "16").ToString();
            try {
                return LockCryptWPFBLL.GetSizedImage(filename, size);
            } catch(Exception ex) {
                Console.WriteLine(string.Format("Error loading image {0} ({1}px): ", filename, size, ex.Message));
            }
            return value;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }

        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) {
            if(values == null || values.Length != 2)
                return values;
            string filename = (values[0] ?? string.Empty).ToString().Trim();
            string size = (values[1] ?? "32").ToString();
            try {
                return LockCryptWPFBLL.GetSizedImage(filename, size);
            } catch(Exception ex) {
                Console.WriteLine(string.Format("Error loading image {0} ({1}px): ", filename, size, ex.Message));
            }
            return values;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Checks a value is not null, returning true if it <b>is not</b> null, and false if it is null.
    /// </summary>
    public class TrueIfNullOrEmptyConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            return value == null || (value as string ?? string.Empty).Trim().Length == 0;
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Checks a value is not null, returning true if it <b>is not</b> null, and false if it is null.
    /// </summary>
    public class TrueIfNotNullConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            return value != null;
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Checks to see if the value given for parameter (ctrl, alt, shift or 'key') is part of the specified key gesture.
    /// </summary>
    public class HotkeyConverter : IValueConverter {
        /// <summary>
        /// Converts a value.
        /// </summary>
        /// <param name="value">The gesture (string or KeyGesture).</param>
        /// <param name="parameter">One of: ctrl, shift, alt or key.</param>
        /// <returns>
        /// A converted value. If the method returns null, the valid null value is used.
        /// </returns>
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            try {
                string keyToCheck = (parameter ?? string.Empty).ToString().ToLowerInvariant();
                if(value == null || keyToCheck.Length == 0) {
                    return value;
                }
                KeyGesture gesture = value as KeyGesture;
                if(gesture == null) {
                    var converter = new System.Windows.Input.KeyGestureConverter();
                    gesture = converter.ConvertFromInvariantString(System.Convert.ToString(value)) as KeyGesture;
                }
                //Console.WriteLine(value + "  -   " + parameter + "  -   " + gesture.DisplayString);
                switch(keyToCheck) {
                    case "ctrl":
                        return (gesture.Modifiers & ModifierKeys.Control) == ModifierKeys.Control;
                    case "shift":
                        return (gesture.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift;
                    case "alt":
                        return (gesture.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt;
                    case "key":
                        return gesture.Key.ToString();
                }
                return gesture.DisplayString;
            } catch {
                return value;
            }
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            KeyGesture gesture = value as KeyGesture;
            if(gesture == null)
                return null;
            var converter = new System.Windows.Input.KeyGestureConverter();
            var converted = converter.ConvertToInvariantString(gesture);
            return converted;
        }
    }

    /// <summary>
    /// Converts a string to a KeyGesture.
    /// </summary>
    public class StringToKeyGestureConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            if(value == null)
                return value;
            try {
                var converter = new System.Windows.Input.KeyGestureConverter();
                KeyGesture gesture = converter.ConvertFromInvariantString(System.Convert.ToString(value)) as KeyGesture;
                return gesture;
            } catch {
                return value;
            }
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            if(targetType == typeof(string)) {
                KeyGesture gesture = value as KeyGesture;
                if(gesture == null)
                    return null;
                var converter = new System.Windows.Input.KeyGestureConverter();
                var converted = converter.ConvertToInvariantString(gesture);
                return converted;
            } else {
                throw new NotImplementedException();
            }
        }
    }

    /// <summary>
    /// Converts a value (IAccount or IGroup) and a parameter ("group" or "account") to a Visibility. Returns Visible if the value is of the parameter's type name,
    /// otherwise <c>false</c>.
    /// </summary>
    public class NestableToVisibilityConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            string nestableType = (parameter ?? string.Empty).ToString();
            if(value == null || !(value is INestable)) {
                return Visibility.Collapsed;
            } else if(value is IAccount && nestableType == "account") {
                return Visibility.Visible;
            } else if(value is IGroup && nestableType == "group") {
                return Visibility.Visible;    
            }
            return Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Converts a CultureInfo to a string representing a flag image for that culture.
    /// </summary>
    public class CultureInfoToFlagConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            if(value == null || !(value is CultureInfo)) {
                return null;
            } else {
                return string.Format("pack://application:,,,/Resources/images/flags/{0}.png", Utils.GetISO3166(value as CultureInfo));
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Provides a breakpoint for debugging
    /// </summary>
    public class DebugConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            return value;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    #region Account view specific
    /// <summary>
    /// Converts the 'Account View' preference settings value to a boolean indicating whether the current setting equals the converter parameter.
    /// </summary>
    public class ViewPreferenceConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            if(value == null || parameter == null) {
                return false;
            }
            try {
                WPFConstants.AccountViews currentView = (WPFConstants.AccountViews)Enum.Parse(typeof(WPFConstants.AccountViews), value.ToString(), true);
                WPFConstants.AccountViews thisView = (WPFConstants.AccountViews)Enum.Parse(typeof(WPFConstants.AccountViews), parameter.ToString(), true);
                return currentView == thisView;
            } catch {
                return false;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            if(value == null || parameter == null) {
                return false;
            }
            try {
                WPFConstants.AccountViews view = (WPFConstants.AccountViews)Enum.Parse(typeof(WPFConstants.AccountViews), parameter.ToString(), true);
                bool preferred = bool.Parse(value.ToString());
                if(preferred) {
                    return view;
                }
                return false;
            } catch {
                return false;
            }
        }
    }

    /// <summary>
    /// Shows either an unobfuscated field or a string of asterisks.
    /// Values[0] = Actual field value
    /// Values[1] = Meta data (whether the field is a password)
    /// Values[2] = <c>true</c> to show the obfuscated value, <c>null</c> or <c>false</c> to show asterisks.
    /// </summary>
    public class ObfuscatedFieldConverter : IMultiValueConverter {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) {
            if(values != null || values.Length == 3) {
                try {
                    string fieldValue = (values[0] ?? string.Empty).ToString();
                    FieldMetaData fieldFlags = (FieldMetaData) Enum.Parse(typeof(FieldMetaData), values[1].ToString(), true);
                    if(FieldBase.GetMetaState(fieldFlags, FieldMetaData.Password) && System.Convert.ToBoolean(values[2])) { // field is hidden
                        return "*********";
                    } else {
                        return fieldValue;
                    }
                } catch {
                }
            }
            return values;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// When used as an IMultiValueConverter:
    /// If the IField supplied (<c>values[0]</c>) is of the field type specified by <c>parameter</c>, returns the field value (<c>values[1]</c>), otherwise  returns null.
    /// 
    /// When used as an IValueConverter:
    /// If the IField supplied by <c>value</c> is of the field type specified by <c>parameter</c>, returns the field value, otherwise  returns null.
    /// </summary>
    public class IsMetaFieldConverter : IMultiValueConverter {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) {
            if(values != null || values.Length == 3 || parameter != null) {
                try {
                    FieldMetaData currentMeta = (FieldMetaData)values[0];
                    FieldMetaData metaToCheck = (FieldMetaData)parameter;
                    if(FieldBase.GetMetaState(currentMeta, metaToCheck)) {
                        return values[1];
                    }
                } catch {
                }
            }
            return values;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            IField field = value as IField;
            FieldMetaData metaToCheck = (FieldMetaData)parameter;
            if(field != null && value != null && FieldBase.GetMetaState(field.Meta, metaToCheck)) {
                return field.Value;
            }
            return null;
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Converts an IEnumerable&lt;IField&gt; to a menu with items which fire the InsertField command with the field name as the parameter.
    /// </summary>
    public class FieldToMenuItemConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            var fields = value as IEnumerable<IField>;
            if(fields == null)
                return value;
            var items = fields.OrderBy(f => f.SortIndex)
                             .Select(f => new MenuItem() {
                                 Command = LockCryptCommands.InsertField,
                                 CommandParameter = f.Name,
                                 Header = f.Name
                             });
            var menu = new ContextMenu();
            if(items.Any()) {
                foreach(MenuItem itm in items) {
                    menu.Items.Add(itm);
                }
            } else {
                menu.Items.Add(new MenuItem() {
                    Header = I18nUtils.GetString("Strings", "None"),
                    IsEnabled = false
                });
            }
            return menu;
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Returns true if the value has the specified meta flag turned on, otherwise false
    /// </summary>
    public class MetaFlagsToBoolConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            if(value != null && parameter != null) {
                try {
                    FieldMetaData dataToCheck = (FieldMetaData)Enum.Parse(typeof(FieldMetaData), parameter.ToString(), true);
                    return FieldBase.GetMetaState(value.ToString(), dataToCheck);
                } catch {
                }
            }
            return false;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Returns <c>Visible</c> if the value has the specified meta flag turned on, otherwise <c>Collapsed</c>
    /// </summary>
    public class MetaFlagsToVisibilityConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            if(value != null && parameter != null) {
                try {
                    FieldMetaData dataToCheck = (FieldMetaData)Enum.Parse(typeof(FieldMetaData), parameter.ToString(), true);
                    return FieldBase.GetMetaState(value.ToString(), dataToCheck) ? Visibility.Visible : Visibility.Collapsed;
                } catch {
                }
            }
            return Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Converts a percentage rating to a score - either 'Very weak', 'Weak', 'Good', 'Strong' or 'Very Strong'
    /// </summary>
    public class RatingToStrengthConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            PasswordAnalyzer.PasswordAnalysis analysis = value as PasswordAnalyzer.PasswordAnalysis;
            if(analysis == null)
                return I18nUtils.GetString("Strings", "NoneSelected");
            try {
                if(analysis.PercentageScore > 100) { analysis.PercentageScore = 100; } else if(analysis.PercentageScore < 0) { analysis.PercentageScore = 0; }
                string strength = string.Empty;
                if(analysis.PercentageScore < 20) {
                    strength = I18nUtils.GetString("Strings", "VeryWeak");
                } else if(analysis.PercentageScore < 40) {
                    strength = I18nUtils.GetString("Strings", "Weak");
                } else if(analysis.PercentageScore < 60) {
                    strength = I18nUtils.GetString("Strings", "Good");
                } else if(analysis.PercentageScore < 80) {
                    strength = I18nUtils.GetString("Strings", "Strong");
                } else if(analysis.PercentageScore <= 100) {
                    strength = I18nUtils.GetString("Strings", "VeryStrong");
                }
                return string.Format("{0} - {1}", Math.Round(analysis.PercentageScore,0), strength);
            } catch {
                return value;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    ///If a value is an account, returns either it's template's name or 'None' if the tempkate name is null/empty. 
    ///Returns nothing if <c>value is a group</c>
    /// </summary>
    public class TemplateNameSanitizer : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            IAccount account = value as IAccount;
            if(account != null) {
                try {
                    return string.IsNullOrEmpty(account.Template.Name) ? I18nUtils.GetString("Strings", "None") : account.Template.Name;
                } catch {
                }
            }
            return string.Empty;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Selects an account or group template for a treeview.
    /// </summary>
    public class TreeTemplateSelector : DataTemplateSelector {
        public DataTemplate GroupTemplate { get; set; }
        public DataTemplate AccountTemplate { get; set; }

        public override DataTemplate SelectTemplate(object item, DependencyObject container) {
            if(item is IGroup) {
                return GroupTemplate;
            } else if(item is IAccount) {
                return AccountTemplate;
            } else {
                return base.SelectTemplate(item, container);
            }
        }
    }

    /// <summary>
    /// Selects either a group or an account template depending on the item
    /// </summary>
    public class NestableTemplateSelector : DataTemplateSelector {
        public DataTemplate GroupLargeIconsTemplate { get; set; }
        public DataTemplate GroupSmallIconsTemplate { get; set; }
        public DataTemplate GroupDetailsTemplate { get; set; }
        public DataTemplate GroupTilesTemplate { get; set; }
        public DataTemplate AccountTemplate { get; set; }

        public override DataTemplate SelectTemplate(object item, DependencyObject container) {
            if(item is IGroup) {
                AccountView accView = Lime49.WPF.Utils.GetParentOfType(container, typeof(AccountView)) as AccountView;
                if(accView != null) {
                    switch (accView.CurrentView) {
                        case WPFConstants.AccountViews.Details:
                            return this.GroupDetailsTemplate;
                        case WPFConstants.AccountViews.LargeIcons:
                            return this.GroupLargeIconsTemplate;
                        case WPFConstants.AccountViews.SmallIcons:
                            return this.GroupSmallIconsTemplate;
                        case WPFConstants.AccountViews.Tiles:
                            return this.GroupTilesTemplate;
                    }
                }
                return GroupSmallIconsTemplate;
            } else if(item is IAccount) {
                return AccountTemplate;
            } else {
                return base.SelectTemplate(item, container);
            }
        }
    }
    #endregion

    #region Converters for the WPF toolkit Datagrid
    public class BoolToOpacityConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            try {
                bool b = (bool)value;
                if(b) return 1; else return 0;
            } catch {
                return 1;
            }
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    public class ObjectToTypeName : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            if(value != null) {
                return value.GetType().Name;
            } else {
                return null;
            }
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            throw new NotImplementedException();
        }
    }
    #endregion
}
